package com.eshipenet.shipnet.edgeboxrpc.grpc;


import com.eshipenet.shipnet.edgebox.IsCmdChannelOn;
import com.eshipenet.shipnet.edgebox.IsDataChannelOn;
import com.eshipenet.shipnet.edgebox.IsOnLine;
import com.eshipenet.shipnet.edgebox.grpc.*;
import com.eshipenet.shipnet.edgeboxrpc.service.EdgeBoxIdGenerator;
import com.eshipenet.shipnet.edgeboxrpc.util.FormatSql;
import com.eshipenet.shipnet.edgeboxrpc.util.GetJObjectUtil;
import com.eshipenet.shipnet.edgeboxrpc.util.PageUtil;
import com.eshipenet.shipnet.edgeboxrpc.util.TimestampToDate;
import com.google.protobuf.Struct;
import com.google.protobuf.Timestamp;
import com.google.protobuf.util.Timestamps;
import io.grpc.stub.StreamObserver;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.cache.query.FieldsQueryCursor;
import org.apache.ignite.cache.query.QueryCursor;
import org.apache.ignite.cache.query.SqlFieldsQuery;
import org.apache.ignite.cache.query.SqlQuery;
import org.json4s.JsonAST;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import scala.Option;
import scala.collection.Seq;
import scala.collection.immutable.List;
import squirrel.JSONQuery;
import squirrel.SqlValue;

import javax.cache.Cache;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;


public class EdgeBoxStateRepoGrpcImpl extends EdgeBoxStateRepoGrpc.EdgeBoxStateRepoImplBase {
    private Logger  logger = LoggerFactory.getLogger("EdgeBoxStateRepoGrpcImpl");
    private IgniteCache<String, com.eshipenet.shipnet.edgebox.EdgeBoxState> cache;
    private EdgeBoxIdGenerator                                              idGenerator;

    public EdgeBoxStateRepoGrpcImpl(IgniteCache<String, com.eshipenet.shipnet.edgebox.EdgeBoxState> cache,
                                    EdgeBoxIdGenerator idGenerator) {
        this.cache = cache;
        this.idGenerator = idGenerator;
    }

    private EdgeBoxRepoGrpcImpl edgeBoxRepoGrpc;


    /**
     * 查询列表
     *
     * @param req
     * @param responseObserver
     */
    public void findAll(EdgeBoxStateFindAllRequest req, StreamObserver<EdgeBoxStateFindAllReply> responseObserver) {

        try {
            logger.info("EdgeBoxStateRepoGrpcImpl.findAll.Filter  {}",req.getFilter().toString());
            EdgeBoxStateFindAllReply reply = findAllInner(req);
            responseObserver.onNext(reply);
            responseObserver.onCompleted();

        } catch (Exception e) {
            responseObserver.onError(e);

        }

    }


    /**
     * 创建
     *
     * @param req
     * @param responseObserver
     */
    public void createOne(EdgeBoxStateCreateOneRequest req, StreamObserver<EdgeBoxStateCreateOneReply> responseObserver) {

        try {
            logger.info("EdgeBoxStateRepoGrpcImpl.createOne.data {}",req.getData());
            EdgeBoxStateCreateOneReply reply = createOneInner(req);
            responseObserver.onNext(reply);
            responseObserver.onCompleted();
        } catch (Exception e) {
            responseObserver.onError(e);

        }
    }


    /**
     * 修改
     *
     * @param req
     * @param responseObserver
     */
    public void updateOne(EdgeBoxStateUpdateOneRequest req, StreamObserver<EdgeBoxStateUpdateOneReply> responseObserver) {

        try {
            logger.info("EdgeBoxStateRepoGrpcImpl.updateOne.data {}",req.getData());
            EdgeBoxStateUpdateOneReply reply = updateOneInner(req);
            responseObserver.onNext(reply);
            responseObserver.onCompleted();
        } catch (Exception e) {
            responseObserver.onError(e);

        }
    }


    /**
     * 删除
     *
     * @param req
     * @param responseObserver
     */
    public void deleteOne(EdgeBoxStateDeleteOneRequest req, StreamObserver<EdgeBoxStateDeleteOneReply> responseObserver) {

        try {
            logger.info("EdgeBoxStateRepoGrpcImpl.deleteOne.id {}",req.getId());
            EdgeBoxStateDeleteOneReply reply = deleteOneInner(req);
            responseObserver.onNext(reply);
            responseObserver.onCompleted();
        } catch (Exception e) {
            responseObserver.onError(e);

        }
    }


    public EdgeBoxStateFindAllReply findAllInner(EdgeBoxStateFindAllRequest req) {

        int limit = req.getFilter().getLimit();
        int offset = req.getFilter().getOffset();

        if (limit == 0) {
            limit = 500;

        }
        if (offset == 0) {
            offset = 1;

        }

        //查询条件
        Struct wheres = req.getFilter().getWhere();

        JsonAST.JObject jObject = GetJObjectUtil.getWhere(wheres);

        //联合查询
        java.util.List<EdgeBoxStateFindAllFilterInclude> in_list = req.getFilter().getIncludeList();

        ArrayList<JsonAST.JValue> arrayList = new ArrayList<JsonAST.JValue>();

        List<JsonAST.JValue> includes_list = scala.collection.JavaConverters.asScalaIterator(arrayList.iterator()).toList();

        JsonAST.JArray jArray = new JsonAST.JArray(includes_list);

        //生成查询列表的sql
        JSONQuery jsonQuery = JSONQuery.apply(new JsonAST.JString("edgeboxstate"),
                Option.apply(jObject),
                Option.apply(new JsonAST.JString("*")),
                Option.apply(jArray),
                Option.apply(null),
                Option.apply(null));

        Map<String, Object> map = FormatSql.getFormatSql(jsonQuery);

        String end_sql = map.get("sql").toString();

        SqlQuery<String, com.eshipenet.shipnet.edgebox.EdgeBox> sql =
                new SqlQuery(com.eshipenet.shipnet.edgebox.EdgeBoxState.class, end_sql);
        Seq<SqlValue> sqlValueSeq = (Seq<SqlValue>) map.get("args");
        sql.setArgs(FormatSql.sqlValueToObject(sqlValueSeq));
        logger.info("query EdgeBoxState list sql  {}",sql);
        QueryCursor cursor = cache.query(sql);

        //生成查询数据数量的sql
        JSONQuery jsonQuery1 = JSONQuery.apply(new JsonAST.JString("edgeboxstate"),
                Option.apply(jObject),
                Option.apply(new JsonAST.JString("count(*) as count")),
                Option.apply(jArray),
                Option.apply(null),
                Option.apply(null));

        Map<String, Object> count_sql = FormatSql.getFormatSql(jsonQuery1);

        String end_query = count_sql.get("sql").toString();

        SqlFieldsQuery sqlFieldsQuery = new SqlFieldsQuery(end_query);

        Seq<SqlValue> sqlValueSeq1 = (Seq<SqlValue>) count_sql.get("args");

        sqlFieldsQuery.setArgs(FormatSql.sqlValueToObject(sqlValueSeq1));
        logger.info("query EdgeBoxState count sql  {}",sqlFieldsQuery);
        //数据总数
        int totalCount = 0;

        try (FieldsQueryCursor<java.util.List<?>> cursor1 = cache.query(sqlFieldsQuery)) {

            for (java.util.List<?> row : cursor1) {
                totalCount = Integer.parseInt(row.get(0).toString());
            }


        }
        //分页工具
        Map<String, Object> page = PageUtil.page(limit, totalCount, offset);
        //起点数据
        int startIndex = (int) page.get("startIndex");
        //结点数据
        int endIndex = (int) page.get("endIndex");

        java.util.List<EdgeBoxStateEdge> list = new ArrayList<>();

        //判断是否有数据，无数据时直接返回
        if (totalCount < 1) {
            //设置分页信息
            PageInfo pageInfo = PageInfo.newBuilder()
                                        .setHasNextPage((Boolean) page.get("hasNextPage"))
                                        .setHasPreviousPage((Boolean) page.get("hasPreviousPage"))
                                        .build();

            EdgeBoxStateFindAllReply reply = EdgeBoxStateFindAllReply.newBuilder()
                    .setReq(req)
                    .addAllEdges(list)
                    .setPageInfo(pageInfo)
                    .setTotalCount(0).build();

            return reply;
        }

        Iterator<Cache.Entry<String, com.eshipenet.shipnet.edgebox.EdgeBoxState>> iterator = cursor.iterator();

        //计数器
        int times = 0;

        while (iterator.hasNext()) {

            Cache.Entry<String, com.eshipenet.shipnet.edgebox.EdgeBoxState> p = iterator.next();


            if (p != null && !p.equals("")) {

                if (list.size() < limit) {
                    if (times >= startIndex && times < endIndex) {

                        EdgeBoxStateEdge edgeBoxEdge = EdgeBoxStateEdge.newBuilder().setNode(EdgeBoxState
                                .newBuilder()
                                .setId(p.getKey())
                                .setCreatedAt(TimestampToDate.dateTotimestamp(p.getValue().getCreatedAt()))
                                .setUpdatedAt(TimestampToDate.dateTotimestamp(p.getValue().getUpdatedAt()))
                                .setInfo(GetJObjectUtil.getData(p.getValue().getData()))
                                .setOnline(EdgeBoxState.isOnline.valueOf(p.getValue().getIsOnLine().name()))
                                .setCmdChannel(EdgeBoxState.isCmdChannelOn.valueOf(p.getValue().getIsCmdChannelOn().name()))
                                .setDataChannel(EdgeBoxState.isDataChannelOn.valueOf(p.getValue().getIsDataChannelOn().name()))
                                .setOnlineAt(TimestampToDate.dateTotimestamp(p.getValue().getOnlineAt()))
                                .setOfflineAt(TimestampToDate.dateTotimestamp(p.getValue().getOfflineAt()))
                        )
                                .setCursor(p.getValue().getId()).build();

                        list.add(edgeBoxEdge);
                    }

                } else {
                    break;
                }
            }
            times++;
        }

        //设置分页信息
        PageInfo pageInfo = PageInfo.newBuilder()
                                    .setHasNextPage((Boolean) page.get("hasNextPage"))
                                    .setHasPreviousPage((Boolean) page.get("hasPreviousPage"))
                                    .setStartCursor(page.get("startIndex").toString())
                                    .setEndCursor(page.get("endIndex").toString()).build();

        EdgeBoxStateFindAllReply reply = EdgeBoxStateFindAllReply.newBuilder()
                                                                 .setReq(req)
                                                                 .addAllEdges(list)
                                                                 .setPageInfo(pageInfo)
                                                                 .setTotalCount(totalCount).build();

        return reply;


    }


    public EdgeBoxStateCreateOneReply createOneInner(EdgeBoxStateCreateOneRequest req) {

        //获取当前时间
        java.sql.Timestamp createdAt = new java.sql.Timestamp(System.currentTimeMillis());
        Timestamp createdAt1 = Timestamps.fromMillis(new Date().getTime());

        Struct data = req.getData().getInfo();
        String data_str = GetJObjectUtil.getData(data);

        String edgeBoxId = req.getData().getEdgeBoxId();

        //判断modelId
        if (edgeBoxId != null && edgeBoxId != "") {

            int count = edgeBoxRepoGrpc.getEdgeBoxCount(edgeBoxId);

            if (count < 1) {
                try {
                    throw new Exception("edgeBoxId查询为空");
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }

        }


        String name = req.getData().getOnline().name();

        java.sql.Timestamp onLineAt = new java.sql.Timestamp(System.currentTimeMillis());
        Timestamp onLineAt1 = Timestamps.fromMillis(new Date().getTime());
        //不为online ,设置时间为null
        if (IsOnLine.OFFLINE.name().equals(name)) {
            onLineAt = null;
            onLineAt1 = null;
        }
        //存进新纪录
        IsOnLine isOnLine = IsOnLine.valueOf(req.getData().getOnline().name());
        IsCmdChannelOn isCmdChannelOn = IsCmdChannelOn.valueOf(req.getData().getCmdChannel().name());
        IsDataChannelOn isDataChannelOn = IsDataChannelOn.valueOf(req.getData().getDataChannel().name());

        String id = this.idGenerator.generate();

        cache.put(id, new com.eshipenet.shipnet.edgebox.EdgeBoxState(
                id,
                req.getData().getEdgeBoxId(),
                createdAt,
                createdAt,
                isOnLine,
                isCmdChannelOn,
                isDataChannelOn,
                onLineAt,
                onLineAt,
                data_str
        ));


        EdgeBoxState edgeBoxState = EdgeBoxState.newBuilder()
                .setId(id)
                .setCreatedAt(createdAt1)
                .setUpdatedAt(createdAt1)
                .setEdgeBoxId(req.getData().getEdgeBoxId())
                .setInfo(req.getData().getInfo())
                .setOnline(EdgeBoxState.isOnline.valueOf(req.getData().getOnline().name()))
                .setCmdChannel(EdgeBoxState.isCmdChannelOn.valueOf(req.getData().getCmdChannel().name()))
                .setDataChannel(EdgeBoxState.isDataChannelOn.valueOf(req.getData().getDataChannel().name()))
                .setOnlineAt(onLineAt1)
                .build();

        return EdgeBoxStateCreateOneReply.newBuilder().setData(edgeBoxState).setReq(req).build();
    }


    public EdgeBoxStateUpdateOneReply updateOneInner(EdgeBoxStateUpdateOneRequest req) {
        //获取当前时间
        java.sql.Timestamp updatedAt = new java.sql.Timestamp(System.currentTimeMillis());
        Timestamp updatedAt1 = Timestamps.fromMillis(new Date().getTime());

        Struct data = req.getData().getInfo();
        String data_str = GetJObjectUtil.getData(data);


        //查询指定数据
        SqlQuery sql = new SqlQuery(com.eshipenet.shipnet.edgebox.EdgeBoxState.class, "id=?");

        QueryCursor<Cache.Entry<Integer, com.eshipenet.shipnet.edgebox.EdgeBoxState>> cursor =
                cache.query(sql.setArgs(req.getData().getId()));
        logger.info("query EdgeBoxState list  by id sql  {}",sql);
        Cache.Entry<Integer, com.eshipenet.shipnet.edgebox.EdgeBoxState> e = cursor.getAll().get(0);

        IsOnLine isOnLine = IsOnLine.valueOf(req.getData().getOnline().name());
        IsCmdChannelOn isCmdChannelOn = IsCmdChannelOn.valueOf(req.getData().getCmdChannel().name());
        IsDataChannelOn isDataChannelOn = IsDataChannelOn.valueOf(req.getData().getDataChannel().name());


        String name = req.getData().getOnline().name();

        //上线
        java.sql.Timestamp onLineAt = new java.sql.Timestamp(System.currentTimeMillis());
        Timestamp onLineAt1 = Timestamps.fromMillis(new Date().getTime());

        //下线
        java.sql.Timestamp offLineAt = new java.sql.Timestamp(System.currentTimeMillis());
        Timestamp offLineAt1 = Timestamps.fromMillis(new Date().getTime());

        //下线
        if (IsOnLine.OFFLINE.name().equals(name)) {
            onLineAt = e.getValue().getOnlineAt();
            onLineAt1 = TimestampToDate.dateTotimestamp(e.getValue().getOnlineAt());
        }

        //上线
        if (IsOnLine.ONLINE.name().equals(name)) {
            offLineAt = onLineAt;
            offLineAt1 = onLineAt1;
        }

        cache.put(req.getData().getId(), new com.eshipenet.shipnet.edgebox.EdgeBoxState(
                req.getData().getId(),
                e.getValue().getEdgeBoxId(),
                e.getValue().getCreatedAt(),
                updatedAt,
                isOnLine,
                isCmdChannelOn,
                isDataChannelOn,
                onLineAt,
                offLineAt,
                data_str
        ));


        EdgeBoxState edgeBoxState = EdgeBoxState.newBuilder()
                .setId(req.getData().getId())
                .setCreatedAt(TimestampToDate.dateTotimestamp(e.getValue().getCreatedAt()))
                .setUpdatedAt(updatedAt1)
                .setEdgeBoxId(e.getValue().getEdgeBoxId())
                .setInfo(req.getData().getInfo())
                .setOnline(EdgeBoxState.isOnline.valueOf(req.getData().getOnline().name()))
                .setCmdChannel(EdgeBoxState.isCmdChannelOn.valueOf(req.getData().getCmdChannel().name()))
                .setDataChannel(EdgeBoxState.isDataChannelOn.valueOf(req.getData().getDataChannel().name()))
                .setOnlineAt(onLineAt1)
                .setOfflineAt(offLineAt1)
                .build();


        EdgeBoxStateUpdateOneReply reply = EdgeBoxStateUpdateOneReply.newBuilder().setData(edgeBoxState).setReq(req).build();

        return reply;

    }


    public EdgeBoxStateDeleteOneReply deleteOneInner(EdgeBoxStateDeleteOneRequest req) {

        //查询指定数据
        SqlQuery sql = new SqlQuery(com.eshipenet.shipnet.edgebox.EdgeBoxState.class, "id=?");

        QueryCursor<Cache.Entry<Integer, com.eshipenet.shipnet.edgebox.EdgeBoxState>> cursor =
                cache.query(sql.setArgs(req.getId()));
        logger.info("query EdgeBoxState list  by id sql  {}",sql);
        Cache.Entry<Integer, com.eshipenet.shipnet.edgebox.EdgeBoxState> e = cursor.getAll().get(0);

        String edgeBoxId = e.getValue().getEdgeBoxId();
        if (edgeBoxId == null) {
            edgeBoxId = "";
        }
        EdgeBoxState edgeBoxState = EdgeBoxState.newBuilder()
                .setId(req.getId())
                .setCreatedAt(TimestampToDate.dateTotimestamp(e.getValue().getCreatedAt()))
                .setUpdatedAt(TimestampToDate.dateTotimestamp(e.getValue().getUpdatedAt()))
                .setEdgeBoxId(edgeBoxId)
                .setInfo(GetJObjectUtil.getData(e.getValue().getData()))
                .setOnline(EdgeBoxState.isOnline.valueOf(e.getValue().getIsOnLine().name()))
                .setCmdChannel(EdgeBoxState.isCmdChannelOn.valueOf(e.getValue().getIsCmdChannelOn().name()))
                .setDataChannel(EdgeBoxState.isDataChannelOn.valueOf(e.getValue().getIsDataChannelOn().name()))
                .setOnlineAt(TimestampToDate.dateTotimestamp(e.getValue().getOnlineAt()))
                .setOfflineAt(TimestampToDate.dateTotimestamp(e.getValue().getOfflineAt()))
                .build();

        SqlFieldsQuery query = new SqlFieldsQuery("delete from edgeboxstate   where id=?");
        cache.query(query.setArgs(req.getId())).getAll();
        logger.info("delete EdgeBoxState   by id sql  {}",sql);
        EdgeBoxStateDeleteOneReply reply = EdgeBoxStateDeleteOneReply.newBuilder().setData(edgeBoxState).setReq(req).build();

        return reply;

    }


}
